package com.oneonefive.educationsystem.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.oneonefive.educationsystem.domain.Student;
import com.oneonefive.educationsystem.domain.User;
import com.oneonefive.educationsystem.dto.Result;
import com.oneonefive.educationsystem.mapper.StudentMapper;
import com.oneonefive.educationsystem.service.StudentService;
import com.oneonefive.educationsystem.service.UserService;
import com.oneonefive.educationsystem.utils.Constant;
import com.oneonefive.educationsystem.utils.RedisUtil;
import com.oneonefive.educationsystem.vo.StudentVo;
import com.oneonefive.educationsystem.vo.UserVo;
import jakarta.annotation.Resource;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@ComponentScan("com/oneonefive/educationsystem")
@Service
public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student>
        implements StudentService {

    final Object lock = new Object();
    @Resource
    StudentMapper studentMapper;
    @Resource
    UserService userService;
    @Resource
    RedisTemplate redisTemplate;

    @Override
    public Result stuList(StudentVo studentVo) {
        long total = studentMapper.getStudentByUserCount(studentVo).size();
        studentVo.setPage((studentVo.getPage() - 1) * 10);
        List<Student> studentByUser = studentMapper.getStudentByUser(studentVo);
        return Result.ok(studentByUser, total);
    }

    @Override
    public Result legitimacy(Student student) {
        if (student.getMajor().length() > 20) {
            return Result.fail("专业名字长度过长");
        }
        if (student.getClazz().length() > 20) {
            return Result.fail("班级名字长度过长");
        }
        return Result.ok();
    }

    @Override
    public Result saveOne(Student student) {
        LocalDate now = LocalDate.now();
        String password = "123456";
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        password = passwordEncoder.encode(password);
        student.getUser().setPassword(password);
        student.getUser().setAccount(getAccount(Integer.toString(now.getYear()), student.getClazz(), student.getMajor()));
        return stuSave(student);
    }

    public Result stuSave(Student student) {
        User user = student.getUser();
        boolean success = userService.saveOne(user);
        if (!success) {
            return Result.ok("创建学生的用户失败");
        }
        UserVo userVo = new UserVo();
        BeanUtils.copyProperties(user, userVo);
        userVo.setPage(1);
        Result result = userService.userList(userVo);
        List<UserVo> list = (List<UserVo>) result.getData();
        userVo = list.get(0);
        BeanUtils.copyProperties(userVo, user);
        student.setUserId(user.getUserId());
        boolean success2 = save(student);
        if (success2) {
            return Result.ok("Student新增成功");
        }
        return Result.fail("Student新增失败");
    }

    @Override
    public Result stuUpdate(Student student) {
        boolean success = userService.updateById(student.getUser());
        if (!success) {
            return Result.fail("学生的用户信息更新失败");
        }
        boolean success2 = updateById(student);
        if (success2) {
            return Result.ok("学生的信息更新成功");
        }
        return Result.fail("学生的信息更新失败");
    }

    @Override
    public Result stuDelete(Integer studentId) {
        Student student = getById(studentId);
        User user = userService.getById(student.getUserId());
        boolean success = removeById(studentId);
        if (!success) {
            return Result.fail("删除学生信息失败");
        }
        boolean success2 = userService.removeById(user.getUserId());
        if (success2) {
            return Result.ok("删除学生成功");
        }
        return Result.fail("删除学生的用户信息失败");
    }

    @Override
    public Result clazzList() {
        List<ConcurrentHashMap<String, Integer>> list = studentMapper.clazzList();
        return Result.ok(list);
    }

    @Override
    public Result uploadExcel(MultipartFile file) throws IOException {
        InputStream inputStream = file.getInputStream();
        Workbook workbook = WorkbookFactory.create(inputStream);
        Sheet sheet = workbook.getSheetAt(0);
        LocalDate now = LocalDate.now();
        Integer job = 3;
        String password = "123456";
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        password = passwordEncoder.encode(password);
        for (Row row : sheet) {
            if (row.getRowNum() == 0) {
                continue;
            }
            String account = Integer.toString(now.getYear());
            String name = row.getCell(0).getStringCellValue();
            String major = row.getCell(1).getStringCellValue();
            String clazz = row.getCell(2).getStringCellValue();
            synchronized (lock) {
                account = getAccount(account, clazz, major);
            }
            User user = new User();
            Student student = new Student();
            user.setAccount(account);
            user.setPassword(password);
            user.setName(name);
            user.setJob(job);
            student.setMajor(major);
            student.setClazz(clazz);
            student.setUser(user);
            stuSave(student);

        }
        return Result.ok("批量载入成功");
    }

    private String getAccount(String account, String clazz, String major) {
        //account:年份+专业+班级+人数
        //年份已经给了
        //专业
        String s = (String) redisTemplate.opsForValue().get(Constant.STUDENT_ACCOUNT_MAJOR_PREFIX + major);
        if (s == null) {
            s = getRedisHashMajor(major);
        }
        account += s;
        //几班
        String classNum = findNumber(clazz);
        classNum = RedisUtil.pedWithZero(classNum, "3");
        account += classNum;
        //人数
        Integer count = (Integer) redisTemplate.opsForValue().get(Constant.STUDENT_ACCOUNT_CLASS_PREFIX + clazz);
        if (count == null) {
            redisTemplate.opsForValue().set(Constant.STUDENT_ACCOUNT_CLASS_PREFIX + clazz, 1);
            count = 1;
        }
        redisTemplate.opsForValue().increment(Constant.STUDENT_ACCOUNT_CLASS_PREFIX + clazz);
        account += RedisUtil.pedWithZero(String.valueOf(count), "3");
        return account;
    }


    private String findNumber(String clazz) {
        Pattern pattern = Pattern.compile("\\d+");
        Matcher matcher = pattern.matcher(clazz);
        if (matcher.find()) {
            return matcher.group();
        }
        return "";
    }


    private String getRedisHashMajor(String key) {
        int h = key.hashCode(); // 使用Java内置的哈希函数\
        h = h * 31; // 乘以一个常数
        h = h + 17; // 加上一个偏移量
        h = h % 10000; // 取模
        h = Math.abs(h); // 取绝对值
        String hString = String.valueOf(h);
        hString = RedisUtil.pedWithZero(hString, "4");
        List<String> list = redisTemplate.opsForList().range(Constant.REDIS_MAJOR_HASH, 0, -1);
        while (list != null && list.contains(hString)) {
            h = (h + 1) % 10000;
            hString = String.valueOf(h);
            hString = RedisUtil.pedWithZero(hString, "4");
        }
        redisTemplate.opsForValue().set(Constant.STUDENT_ACCOUNT_MAJOR_PREFIX + key, hString);
        redisTemplate.opsForList().rightPush(Constant.REDIS_MAJOR_HASH, hString);
        return hString;
    }


}




